package com.blog.aspect;

import com.blog.Utils.IpUtils;
import com.blog.Utils.RedisKeyUtil;
import com.blog.bean.dto.PostDTO;
import com.blog.exception.ServiceException;
import com.blog.bean.vo.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Objects;

/**
 * @author 任浩
 * @version 1.0
 *
 * 这是进行浏览量操作的增强类。

 * todo
 * 注意：浏览量的增强我们使用redis的HyperLogLog数据结构来存储值，因为它是基于基数统计的，
 * 并且在并发情况下是线程安全的。redis对命令的操作是单线程的，所以并发情况下是线程安全的。
 * 浏览量我们每天使用定时任务更新一次到数据库，但是更新浏览量通过获取数据库的浏览量和redis的浏览量加起来。
 *
 */
@Slf4j
@Aspect
@Component
public class ViewCount {

    @Autowired
    private RedisUtils redisUtils;

    /**
     * 获取当前的ServletRequest
     * @return
     */
    protected HttpServletRequest servletRequest() {
        return ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
    }

    @Pointcut("@annotation(com.blog.annotion.ViewCountAnnotation)")
    public void pointCut(){
    }

    @Before("pointCut()")
    public void before(JoinPoint joinPoint){
        log.info("浏览量增强类实现");
        //得到该增强方法的入参
        Object[] args = joinPoint.getArgs();
        PostDTO postDTO = (PostDTO) args[0];
        log.info("得到传递的参数为：{}",postDTO);

        try {
            //得到Request，获取ip地址，
            HttpServletRequest request = servletRequest();
            String ipAddress = IpUtils.getIpAddress(request);
            log.info("获取到的ip地址为：{}" , ipAddress);
            //把当前ip存入redis HyperLogLog中。
            String key  = RedisKeyUtil.getViewCountKey(postDTO.getId());
            log.info("要存入redis的浏览量的key为：{}",key);
            Long l = redisUtils.setViewCount(key, ipAddress);
            if(l == 0){
                log.info("该Ip:{} ，已经访问过了，算入了浏览量统计",ipAddress);
            }
            log.info("设置浏览量成功");
        }
        catch (Exception e){
            e.printStackTrace();
            throw new ServiceException("存放浏览量数值失败: " + e.getMessage());
        }
    }
}
